import { mapState } from "vuex"
import Wrap from "./Wrap"
import { mouseStatus, canvasId  } from "../../lib/const"
import { addSnapshot,getIsComponentStyleChange,setSelectedComponent,getComponentListByKeys, setMultipleKeys } from "../../lib/utils"
// import render from "../../lib/render"
import ComponentRender from "./ComponentRender"
import { deepCopy, parse, ergodicList, removeComponentByKey,updateComponentKey, getComponentByKey, getOffsetByCanvas } from "../../lib/utils"
import Contextmenu from "./Contextmenu"
import Marking from "./Marking"
import initEvent from "./event"
import EventBus from "../../EventBus"
import Multiple from "./Multiple"
import { componentToPx, componentToPercentage } from "../../lib/unit"
import { getBaseAnalysisComponent,setAnalysisComponentListLinkage,getAllAnalysisComponentByEditType } from "../../lib/analysisData"
import { getTableList } from "../../lib/table"
import { getDateList } from "../../lib/date"
import Detailed from "../Detailed"
import "./index.less"

let selectedMouseOffset = {} // 当鼠标按下时, 鼠标距离当前点击元素左上角的偏移
let mouseZoomStart = {}

let isMouseDragDown = false // 是否按住组件(非zoom-point),准备拖拽
let isMouseZoomDown = false // 是否按住zoom-point,准备拖拽zoom-point
let isMultipleDown = false // 是否按住画布,准备拖动鼠标开始绘制多选框
let selectZoomIndex // 当前选中的zoom-point
let selectDropComponent = null // 当前准备放入组件的组件
let dragSelectedComponentKey = ''

const ADD_KEY = '0000'
export default {
  data() {
    return {
      canvasComponentList: [],
      mouseStatus,
      isContextmenuShow: false,
      contextmenuPosition: {},
      contextmenuType: "component",
      canvasId,
      isCanvasDrop: false,
      multipleStartPosition: {},
      multipleEndPosition: {},
      isMultipleShow: false
    }
  },
  computed: {
    ...mapState('lowCode', {
      mouseState: state => state.mouseState,
      selectedComponent: state => state.selectedComponent,
      multipleKeys: state => state.multipleKeys
    })
  },
  components: {
    Wrap,
    Contextmenu,
    Marking,
    Multiple,
    Detailed
  },
  created(){
    initEvent(this)
    
  },
  methods: {
    handleDrop(event){
      event.preventDefault()
      console.log(event, event.dataTransfer.getData("data"))
      const {data, mouseOffset, type} = parse(event.dataTransfer.getData("data"))
      let component = null
      
      if(type === 'analysis'){
        component = getBaseAnalysisComponent(data)
      }
      else {
        component = data
      }
      component.key = updateComponentKey(component.id)
      // 组件原点是左上角
      // 因此,组件坐标为 offsetX - 当前鼠标距离当前组件原点的距离
      const {x, y} = mouseOffset
      component.style.left = event.offsetX - x
      component.style.top = event.offsetY - y
      // 如果鼠标释放时,鼠标的位置还在isDrap的组件内,那么就将组件放入isDrap的组件内
      console.log(selectDropComponent, component)
      if(selectDropComponent){
        this.addChildItem(selectDropComponent,component, 'add')
      }

      this.setCanvasComponentList()
      this.setSelectedComponent()
      setMultipleKeys()

      this.saveSnapshot({
        canvasComponentList: this.canvasComponentList,
      })
      this.$store.commit("lowCode/setMouseStatusChange", mouseStatus.DEFAULT)

    },
    handleDragover(event){
      event.preventDefault()
      this.getRadial(event.offsetX, event.offsetY, ADD_KEY )
    },
    // 点击组件
    handleComponentMouseDown(event, item){
      event.preventDefault()
      event.stopPropagation()
      
      const {type, index} = event.target.dataset
      // console.log(type,event)
      // 如果没有这个定时器，在input修改数据后，立即点击组件，会有触发selectedComponent(即input)change事件的bug
      // setTimeout(()=> {
        // this.setSelectedComponent(1, {
        //   data: item//getComponentByKey(item.key),
        // })  
        if(event.button === 2){
          this.contextmenuPosition = {
            left: `${event.clientX  }px`,
            top: `${event.clientY  }px`,
            offsetX: event.offsetX,
            offsetY: event.offsetY,
            clientX: event.clientX,
            clientY: event.clientY
          }
          this.contextmenuType = "component"
          this.isContextmenuShow = true
        }
      // })
      let museStatus = mouseStatus.DEFAULT
      // 必须要先选中组件,zoom-point才会显示
      if(type === "zoom-point"){
        this.setSelectedComponent(1, {
          data: item//getComponentByKey(item.key),
        }) 
        isMouseZoomDown = true
        // 开始拖拽时的初始位置
        mouseZoomStart = {
          x: event.clientX,
          y: event.clientY
        }
        museStatus = mouseStatus.ZOOM
        selectZoomIndex = index

      }
      else if(type === "drag-wrap"){
        dragSelectedComponentKey = item.key
        if(this.multipleKeys.length <= 1){
          this.setSelectedComponent(1, {
            data: item//getComponentByKey(item.key),
          }) 
        }
        
        selectedMouseOffset = {
          x: event.clientX,
          y: event.clientY
        }
        museStatus = mouseStatus.DRAG
        isMouseDragDown = true
      }
      else {
        this.setSelectedComponent(1, {
          data: item//getComponentByKey(item.key),
        }) 
        // museStatus = mouseStatus.ADD_DRAG

      }

      this.$store.commit("lowCode/setMouseStatusChange", museStatus)

    },
    // 点击画布
    handleMouseDown(event){
      console.log(event)
      event.preventDefault()
      // event.stopPropagation()
      // 如果是右键点击,则显示右键菜单
      if(event.button === 2){
        this.contextmenuPosition = {
          left: `${event.clientX  }px`,
          top: `${event.clientY  }px`,
          offsetX: event.offsetX,
          offsetY: event.offsetY,
          clientX: event.clientX,
          clientY: event.clientY
        }
        this.contextmenuType = "map"
        this.isContextmenuShow = true
        this.setSelectedComponent()
      }
      else {
        const {type, index} = event.target.dataset
        console.log(type,event)
        // 如果点击的是画布,则将已选择组件置空,并显示多选绘制框
        if(type === "map"){
          this.setSelectedComponent()
          
          // museStatus = mouseStatus.DEFAULT
          // 如果当前多选框没有显示
          if(!this.isMultipleShow){
            // 显示多选框
            this.isMultipleShow = true
            
            isMultipleDown = true
            // 并记录当前位置
            this.multipleStartPosition = {
              clientX: event.clientX,
              clientY: event.clientY,
              offsetX: event.offsetX,
              offsetY: event.offsetY
            }
          }
          else {
            // 隐藏多选框
            this.isMultipleShow = false
            isMultipleDown = false
            // 并清空之前的位置信息
            this.multipleStartPosition = {}
            this.multipleEndPosition = {}
            
          }
  
        }
        else {
        }
        
      }
      


    },
    handleMouseMove(event){
      event.preventDefault()
      event.stopPropagation()
      const {type} = event.target.dataset
      // this.$store.commit("lowCode/setMouseStatusChange", mouseStatus.ADD_DRAG)
      // 如果正在拖拽组件
      if(isMouseDragDown){
        // 新位置 = 当前鼠标距离画布左上角的位置 - 偏移量(即鼠标位置距离当前选中元素原点的偏移量)
        const {x,y} = selectedMouseOffset
        const {
          canvasComponentList,
          multipleKeys
        } = this
        const selectedComponents = getComponentListByKeys(canvasComponentList, multipleKeys)
        selectedComponents.forEach(component => {
          const {
            left,
            top
          } = component.style
          // 获取鼠标的偏移量
          const offsetX = event.clientX - x
          const offsetY = event.clientY - y
          // 获取新坐标
          const newLeft = left + offsetX
          const newTop = top + offsetY 
          const {
            left: pLeft,
            top: pTop
          } = componentToPercentage({
            ...component.style,
            left: newLeft,
            top: newTop
          })
          component.style.left = pLeft
          component.style.top = pTop
        })

        // 获取当前鼠标下方的所有组件,并将最上层的组件高亮
        // console.log(event)
        this.getRadial(event.clientX, event.clientY, dragSelectedComponentKey)

        
        // 然后将现在的位置赋值给初始位置
        selectedMouseOffset = {
          x: event.clientX,
          y: event.clientY
        }


      }
      // 如果正在拉伸缩放左键
      if(isMouseZoomDown){ // typeList.includes(type) &&
        const selectedComponent = this.selectedComponent
        const {x,y} = mouseZoomStart
        const offsetX = event.clientX - x
        const offsetY = event.clientY - y
        let newWidth; let newHeight; let newLeft; let newTop
        const {
          width,height,top,left
        } = componentToPx(selectedComponent.style)
        switch (selectZoomIndex) {
          case "0":// left, top
            newWidth = width - offsetX
            newHeight = height - offsetY
            newLeft = left + offsetX
            newTop = top + offsetY
            break
          case "1":// top
            newWidth = width
            newHeight = height - offsetY
            newLeft = left
            newTop = top + offsetY
            break
          case "2":
            newWidth = width + offsetX
            newHeight = height - offsetY
            newLeft = left
            newTop = top + offsetY
            break
          case "3":
            newWidth = width + offsetX
            newHeight = height
            newLeft = left
            newTop = top
            break
          case "4":
            newWidth = width + offsetX
            newHeight = height + offsetY
            newLeft = left
            newTop = top
            break
          case "5":
            newWidth = width
            newHeight = height + offsetY
            newLeft = left
            newTop = top
            break
          case "6":
            newWidth = width - offsetX
            newHeight = height + offsetY
            newLeft = left + offsetX
            newTop = top
            break
          case "7":
            newWidth = width - offsetX
            newHeight = height
            newLeft = left + offsetX
            newTop = top
            break
          default:
            break
        }
        console.log(y, event.clientY, top)
        // 然后将现在的位置赋值给初始位置
        mouseZoomStart = {
          x: event.clientX,
          y: event.clientY
        }
        
        const {
          width: pWidth,
          height: pHeight,
          top: pTop,
          left: pLeft
        } = componentToPercentage({
          ...selectedComponent.style,
          width: newWidth,
          height: newHeight,
          top: newTop,
          left: newLeft
        })
        const newComponent = {
          ...selectedComponent,
          style: {
            ...selectedComponent.style,
            width: pWidth,
            height: pHeight,
            left: pLeft,
            top: pTop
          },
        }
        this.$store.commit("lowCode/setWrapStyle", newComponent.style)

      }
      // 如果点击了画布,正在多选组件
      if(isMultipleDown){
        // 更新结束位置
        this.multipleEndPosition = {
          clientX: event.clientX,
          clientY: event.clientY,
          offsetX: event.offsetX,
          offsetY: event.offsetY
        }
      }
      else {
        // this.$store.commit("lowCode/setSelectedComponent", {});
      }

    },
    handleMouseUp(event){
      const {type, index} = event.target.dataset
      isMouseDragDown = false
      isMouseZoomDown = false
      selectZoomIndex = undefined
      
     
      // 如果鼠标释放时,鼠标的位置还在isDrap的组件内,那么就将组件放入isDrap的组件内
      if(selectDropComponent){
        this.addChildItem(selectDropComponent, this.selectedComponent)
      }
      this.resetMultiple()
      // else if(selectDropComponent === -1) {
      //   // 添加到最外层
      //   this.setCanvasComponentList(1, this.selectedComponent)
      // }
      
      ergodicList(this.canvasComponentList, element => {
        if(element.key === this.selectedComponent.key){
          element = deepCopy(this.selectedComponent)
        }
      })
      
      this.$store.commit("lowCode/setMouseStatusChange", mouseStatus.DEFAULT)
      const isComponentChange = getIsComponentStyleChange()
      if(isComponentChange){ // 发生更改
        this.saveSnapshot({
          canvasComponentList: this.canvasComponentList,
        })
      }
      if(event.button !== 2 && type !== "contextmenu"){
        this.isContextmenuShow = false
      }
      // this.$store.commit("lowCode/setMouseStatusChange", mouseStatus.DEFAULT)
      event.preventDefault()
      event.stopPropagation()
    },
    handleContextmenu(event){
      
      event.preventDefault()
      
    },
    /**
     * 重置多选框
     */
    resetMultiple(){
      if(isMultipleDown){
        this.$refs.multipleRef.setSelectComponents()
        this.isMultipleShow = false
        this.multipleStartPosition = {}
        this.multipleEndPosition = {}
      }
      isMultipleDown = false

      
      
      
    },
    /**
     * 将当前组件作为子组件添加入drop组件内
     * @param {*} dropItem 接收当前组件的组件
     * @param { Component } selectComponent  当前组件
     * @param {*} type  添加方式, 'add', 'move'
     */
    addChildItem(dropItem, selectComponent, type = 'move'){
      
      const {
        canvasComponentList,
        multipleKeys
      } = this
      if(type === 'add'){
        this.appendItem(dropItem, selectComponent, type = 'add')
      }
      else {
        // 当前选中的所有组件
        const selectedComponents = getComponentListByKeys(canvasComponentList, multipleKeys)
        selectedComponents.forEach(componentItem => {
          this.appendItem(dropItem, componentItem, type = 'move')
        })
      }
      
    },
    appendItem(dropItem, selectComponent, type = 'move'){
      let children
      let dropChild
      const {
        canvasComponentList
      } = this
      const {
        id,
        style,
        key
      } = selectComponent
      if(dropItem === -1){
        // 说明应当放到最外层
        dropChild = {
          key: canvasId
        }
        children = canvasComponentList
      }
      else {
        dropChild = dropItem
        const {
          value,
          list
        } = dropChild.props
        children = list.find(item => item.value === value).children
        
      }
      // 当前鼠标位置
      let left 
      let top 
      if(type === 'move'){
        const {
          offsetLeft,
          offsetTop
        } = getOffsetByCanvas(document.getElementById(key))
        left = offsetLeft
        top = offsetTop
      }
      else if(type === 'add'){
        left = style.left
        top = style.top
      }
      
      const {
        offsetLeft: parentLeft,
        offsetTop: parentTop
      } = getOffsetByCanvas(document.getElementById(dropChild.key)) 
      const newLeft = left - parentLeft
      const newTop = top - parentTop
      const tempKey = updateComponentKey(id)
      const component = deepCopy({
        ...selectComponent,
        key: tempKey,
        style: {
          ...style,
          ...componentToPercentage({
            ...style,
            left: newLeft,
            top: newTop
          })
        }
      })
      children.push(component)
      // 然后将canvasComponentList里的selectedComponent删除
      removeComponentByKey(canvasComponentList, key)
      component.key = key
      // 清空selectedComponent
      this.setSelectedComponent()
      // setMultipleKeys()
      ergodicList(canvasComponentList, element=> {
        element.isDrop = false
      })
      this.isCanvasDrop = false
      selectDropComponent = null
      this.setCanvasComponentList()
    },
    /**
     * 更新业务组件相关数据
     */
    updateAnalysisComponentData(){
      // 获取所有业务组件
      const analysisComponentList = getAllAnalysisComponentByEditType(true)
      // 更新下拉框的表和字段的列表
      getTableList(analysisComponentList)
      // 更新日期选择器的表和字段的列表
      getDateList(analysisComponentList)
      // 更新所有业务组件联动设置
      setAnalysisComponentListLinkage(analysisComponentList)
    },
    /**
     * 保存快照
     */
    saveSnapshot(data){
      this.updateAnalysisComponentData()

      const {
        pageSetting,
        canvasComponentList
      } = this.$store.state.lowCode
      const saveData = {
        pageSetting: data.pageSetting || pageSetting,
        canvasComponentList: data.canvasComponentList || canvasComponentList,
      } 
      addSnapshot('all', deepCopy(saveData))
    },
    /**
     * 修改componentListChange
     * @param {*} type 修改类型,1: push,2: 替换整个data
     * @param {*} data push的item或者新数据
     * @param {*} isUpdate 是否需要更新
     */
    setCanvasComponentList(type, data, isUpdate){
      switch(type){
        case 1:
          this.canvasComponentList.push(data)
          break
        case 2:
          // this.$set(this.canvasComponentList, index, data)
          this.canvasComponentList = data
          if(isUpdate){
            this.$forceUpdate()
            // 如果此时有选择组件,那么还需要给selectedComponent重新赋值(双向绑定)
            if(this.selectedComponent.key){
              const selectedComponent = getComponentByKey(this.canvasComponentList,this.selectedComponent.key)
              // 如果现在组件列表里搜不到已选择组件,就将当前组件置空
              if(selectedComponent){
                this.setSelectedComponent(1, {
                  data: selectedComponent
                })
              }
              else {
                this.setSelectedComponent()
              }
              
            }
  
          }
          break
        default:
          // this.canvasComponentList = data
      }
      
      // 向其他组件分发组件变动
      EventBus.$emit("canvasComponentListChange", this.canvasComponentList)
      this.$store.commit('lowCode/setCanvasComponentList', this.canvasComponentList)
    },
    /**
     * 修改selectedComponent
     * @param {*} type 修改类型,1: 修改,2: 清空
     * @param {*} option 修改的数据 
     */
    setSelectedComponent(type, option = {}){
      // 获取所有业务组件,来更新表和字段的列表
      this.updateAnalysisComponentData(true)
      setSelectedComponent(type, option)
    },
    /**
     * 获取当前鼠标坐标下的所有组件
     * @param {*} mouseAbsLeft 鼠标x值(绝对位置)
     * @param {*} mouseAbsTop 鼠标y值(绝对位置) 
     * @param {*} selectKey 当前key
     */
    getRadial(mouseAbsLeft, mouseAbsTop, selectKey){
      // console.log(mouseLeft,mouseTop)
      const {
        canvasComponentList
      } = this
      // 所有同级或者同级的子组件
      const componentList = canvasComponentList
      const radialComponentList = this.getComponentAddress(componentList, {
        left: mouseAbsLeft, 
        top: mouseAbsTop
      },selectKey,[]) || []
      let isCanvasDrop = false
      // console.log(radialComponentList)
      if(radialComponentList.length === 0){
        // 说明当前鼠标在最外层

        // 如果组件本身就在最外层,那么不做处理
        if(canvasComponentList.find(element => element.key === selectKey)){
          selectDropComponent = null
          isCanvasDrop = false
        }
        else {
          // 将组件放到最外层
          selectDropComponent = -1
          isCanvasDrop = true
        }
        
      }
      else {
        const dropComponent = radialComponentList[radialComponentList.length - 1]
        // 判断要drop的组件是不是自己的父节点
        const {
          list,
          value
        } = dropComponent.props
        const children = ((list || []).find(item => value === item.value) || {}).children
        if((children || []).find(item => item.key === selectKey)){
          // 要drop的组件是自己的父节点
          selectDropComponent== null
        }
        else {
          dropComponent.isDrop = true
          selectDropComponent = dropComponent
        }
        
      }
      this.isCanvasDrop = isCanvasDrop
    },
    /**
     * 获取当前鼠标下的所有c-tabs组件(不包括自己)
     * @param {*} list 
     * @param {*} mouse 
     * @param {*} selectKey 
     * @param {*} radialComponentList 
     * @returns 
     */
    getComponentAddress(list, mouse, selectKey, radialComponentList){
      list.forEach(element => {
        const {
          tag,
          style,
          props,
          key
        } = element
        element.isDrop = false
        if(tag === "c-tabs"){
          const {
            width, height
          } = componentToPx(style)
          const {
            list,
            value
          } = props
          const children = ((list || []).find(item => value === item.value) || {}).children
          const bool = this.getMouseIsStayWrap(selectKey, {
            width, height, key
          }, mouse)
          // 当前元素是否在element范围内,且element不是当前元素
          if(bool && element.key !== selectKey){
            
            radialComponentList.push(element)
          }
          
          children && this.getComponentAddress(children, mouse,selectKey, radialComponentList)
        }
        else {
          
          
        }
      })
      return radialComponentList
    },
    /**
     * 判断鼠标在不在wrap里
     * @param {*} selectKey 
     * @param {*} wrap 
     * @param {*} mouse
     * @returns 
     */
    getMouseIsStayWrap(selectKey, wrap, mouse){
      let mouseLeft
      let mouseTop
      // console.log(selectKey, wrap, mouse)
      if(ADD_KEY === selectKey){
        const {
          left,
          top
        } = mouse
        mouseLeft = left
        mouseTop = top
      }
      else {
        const {
          offsetLeft,
          offsetTop
        } = getOffsetByCanvas(document.getElementById(selectKey)) //mouse
        mouseLeft = offsetLeft
        mouseTop = offsetTop
      }
      
      const {
        width, height, key
      } = wrap
      const {
        offsetLeft: left,
        offsetTop: top
      } = getOffsetByCanvas(document.getElementById(key))
      const minLeft = left
      const minTop = top
      const maxLeft = left + width
      const maxTop = top + height
      // console.log(minLeft, mouseLeft, maxLeft)
      return mouseLeft >= minLeft && mouseLeft <= maxLeft && mouseTop >= minTop && mouseTop <= maxTop
    },
    
    

    
  },
  render(h){
    const {
      mouseState, mouseStatus, selectedComponent,isContextmenuShow,multipleKeys,
      contextmenuPosition,canvasComponentList,isCanvasDrop,isMultipleShow,
      multipleStartPosition,multipleEndPosition,
      contextmenuType,
      handleDrop,
      handleDragover,
      handleMouseDown,
      handleMouseMove,
      handleMouseUp,
      handleContextmenu,
      handleComponentMouseDown
    } = this
    return (
      <div id={canvasId} class={`canvas ${isCanvasDrop ? 'drop' : ''} ${mouseState === mouseStatus.DRAG || mouseState === mouseStatus.ZOOM ? 'dragenter' : ''}`} onDrop={handleDrop} ondragover={handleDragover}
        onMousedown={handleMouseDown}
        onMousemove={handleMouseMove}
        onMouseup={handleMouseUp}
        onContextmenu={handleContextmenu}>
        <div
          class={`position-box ${mouseState === mouseStatus.ADD_DRAG ? 'dragenter' : ''}`}>
        </div>
        <div class="wrap-list" data-type="map">
          <ComponentRender list={canvasComponentList} isEdit={true} multipleKeys={multipleKeys} selectedComponent={selectedComponent} handleComponentMouseDown={handleComponentMouseDown}  />
          <Marking />

        </div>
        <Contextmenu type={contextmenuType} isShow={isContextmenuShow} position={contextmenuPosition} />
        <Multiple ref="multipleRef" multipleStartPosition={multipleStartPosition} multipleEndPosition={multipleEndPosition} isShow={isMultipleShow} />
        <Detailed ref="detailedRef" />
      </div>
    )
  }
}

